From b2c21f09e3df79fb32301d023b97039e277a45ec Mon Sep 17 00:00:00 2001 From: robertl Date: Wed, 13 Aug 2008 16:54:40 +0000 Subject: [PATCH] Bring libusb sources inline for Mac to avoid binary compat horrors, ease building source. --- configure | 32 +- configure.in | 29 +- mac/libusb/README | 13 + mac/libusb/darwin.c | 1264 ++++++++++++++++++++++++++++++++++++++ mac/libusb/descriptors.c | 520 ++++++++++++++++ mac/libusb/error.c | 36 ++ mac/libusb/error.h | 31 + mac/libusb/usb.c | 307 +++++++++ mac/libusb/usb.h | 339 ++++++++++ mac/libusb/usbi.h | 74 +++ 10 files changed, 2611 insertions(+), 34 deletions(-) create mode 100644 mac/libusb/README create mode 100644 mac/libusb/darwin.c create mode 100644 mac/libusb/descriptors.c create mode 100644 mac/libusb/error.c create mode 100644 mac/libusb/error.h create mode 100644 mac/libusb/usb.c create mode 100644 mac/libusb/usb.h create mode 100644 mac/libusb/usbi.h diff --git a/configure b/configure index 40d34106f..426b8b87b 100755 --- a/configure +++ b/configure @@ -4177,6 +4177,20 @@ echo "${ECHO_T}USB skipped" >&6; } USB_LIBS=-lsetupapi fi ;; + *-*-darwin*) + GBSER=gbser_posix.o + OSJEEPS="jeeps/gpslibusb.o \ + mac/libusb/darwin.o \ + mac/libusb/descriptors.o \ + mac/libusb/error.o \ + mac/libusb/usb.o " + USB_LIBS="-framework IOKit -framework CoreFoundation" + cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBUSB 1 +_ACEOF + + CFLAGS="$CFLAGS -Imac/libusb/" + ;; *) GBSER=gbser_posix.o { echo "$as_me:$LINENO: checking for libusb" >&5 @@ -4303,23 +4317,7 @@ _ACEOF fi - # Override libusb for Darwin to reduce external - # runtime requirement. - case "$target" in - *-*-darwin*) - if test "x$ac_cv_lib_usb_usb_interrupt_read" = "xyes" ; then - USB_LIBS="`libusb-config --prefix`/lib/libusb.a -framework IOKit -framework CoreFoundation" - LDFLAGS=$OLDFLAGS - CDFLAGS=$OCDFLAGS - OSJEEPS=jeeps/gpslibusb.o - else - OSJEEPS=jeeps/gpsusbstub.o - fi - ;; - *) - OSJEEPS=jeeps/gpslibusb.o - ;; - esac + OSJEEPS=jeeps/gpslibusb.o CFLAGS="$OCFLAGS" # LIBS="$LIBS `libusb-config --libs`" else diff --git a/configure.in b/configure.in index 19edc2ffa..d2cfb62c3 100644 --- a/configure.in +++ b/configure.in @@ -159,6 +159,17 @@ case "$target" in USB_LIBS=-lsetupapi fi ;; + *-*-darwin*) + GBSER=gbser_posix.o + OSJEEPS="jeeps/gpslibusb.o \ + mac/libusb/darwin.o \ + mac/libusb/descriptors.o \ + mac/libusb/error.o \ + mac/libusb/usb.o " + USB_LIBS="-framework IOKit -framework CoreFoundation" + AC_DEFINE(HAVE_LIBUSB, 1) + CFLAGS="$CFLAGS -Imac/libusb/" + ;; *) GBSER=gbser_posix.o AC_MSG_CHECKING(for libusb) @@ -179,23 +190,7 @@ case "$target" in [USB_LIBS="`libusb-config --libs`"] # ,[AC_MSG_ERROR([libusb >= 0.1.8 is needed])] ) - # Override libusb for Darwin to reduce external - # runtime requirement. - case "$target" in - *-*-darwin*) - if test "x$ac_cv_lib_usb_usb_interrupt_read" = "xyes" ; then - USB_LIBS="`libusb-config --prefix`/lib/libusb.a -framework IOKit -framework CoreFoundation" - LDFLAGS=$OLDFLAGS - CDFLAGS=$OCDFLAGS - OSJEEPS=jeeps/gpslibusb.o - else - OSJEEPS=jeeps/gpsusbstub.o - fi - ;; - *) - OSJEEPS=jeeps/gpslibusb.o - ;; - esac + OSJEEPS=jeeps/gpslibusb.o CFLAGS="$OCFLAGS" # LIBS="$LIBS `libusb-config --libs`" else diff --git a/mac/libusb/README b/mac/libusb/README new file mode 100644 index 000000000..6f1b72af7 --- /dev/null +++ b/mac/libusb/README @@ -0,0 +1,13 @@ +This is libusb-0.1.12 with an updated darwin.c that lets USB Garmins +work with 10.4.10 and later. Since we have such problems with people +getting libusb successfully built - between the Universal Build issues +and the fact that we have to work hard to go find where it's installed +and unravel the shared library thing -it's easier to just include it +here. + +This code is covered under GPL. + +This is meant to be a stop-gap until we can get rid of libusb and use +the IoKit framework natively. + +08-11-08 robertlipe diff --git a/mac/libusb/darwin.c b/mac/libusb/darwin.c new file mode 100644 index 000000000..08b39a4e5 --- /dev/null +++ b/mac/libusb/darwin.c @@ -0,0 +1,1264 @@ +/* + * Darwin/MacOS X Support + * + * (c) 2002-2006 Nathan Hjelm + * + * (06/26/2006): + * - Bulk functions no longer use async transfer functions. + * (04/17/2005): + * - Lots of minor fixes. + * - Endpoint table now made by claim_interface to fix a bug. + * - Merged Read/Write to make modifications easier. + * (03/25/2005): + * - Fixed a bug when using asynchronous callbacks within a multi-threaded application. + * (03/14/2005): + * - Added an endpoint table to speed up bulk transfers. + * 0.1.11 (02/22/2005): + * - Updated error checking in read/write routines to check completion codes. + * - Updated set_configuration so that the open interface is reclaimed before completion. + * - Fixed several typos. + * 0.1.8 (01/12/2004): + * - Fixed several memory leaks. + * - Readded 10.0 support + * - Added support for USB fuctions defined in 10.3 and above + * (01/02/2003): + * - Applied a patch by Philip Edelbrock that fixes a bug in usb_control_msg. + * (12/16/2003): + * - Even better error printing. + * - Devices that cannot be opened can have their interfaces opened. + * 0.1.6 (05/12/2002): + * - Fixed problem where libusb holds resources after program completion. + * - Mouse should no longer freeze up now. + * 0.1.2 (02/13/2002): + * - Bulk functions should work properly now. + * 0.1.1 (02/11/2002): + * - Fixed major bug (device and interface need to be released after use) + * 0.1.0 (01/06/2002): + * - Tested driver with gphoto (works great as long as Image Capture isn't running) + * 0.1d (01/04/2002): + * - Implimented clear_halt and resetep + * - Uploaded to CVS. + * 0.1b (01/04/2002): + * - Added usb_debug line to bulk read and write function. + * 0.1a (01/03/2002): + * - Driver mostly completed using the macosx driver I wrote for my rioutil software. + * + * Derived from Linux version by Richard Tobin. + * Also partly derived from BSD version. + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +/* standard includes for darwin/os10 (IOKit) */ +#include +#include +#include +#include + +#include "usbi.h" + +/* some defines */ +/* IOUSBInterfaceInferface */ +#if defined (kIOUSBInterfaceInterfaceID220) + +// #warning "libusb being compiled for 10.4 or later" +#define usb_interface_t IOUSBInterfaceInterface220 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 +#define InterfaceVersion 220 + +#elif defined (kIOUSBInterfaceInterfaceID197) + +// #warning "libusb being compiled for 10.3 or later" +#define usb_interface_t IOUSBInterfaceInterface197 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 +#define InterfaceVersion 197 + +#elif defined (kIOUSBInterfaceInterfaceID190) + +// #warning "libusb being compiled for 10.2 or later" +#define usb_interface_t IOUSBInterfaceInterface190 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 +#define InterfaceVersion 190 + +#elif defined (kIOUSBInterfaceInterfaceID182) + +// #warning "libusb being compiled for 10.1 or later" +#define usb_interface_t IOUSBInterfaceInterface182 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 +#define InterfaceVersion 182 + +#else + +/* No timeout functions available! Time to upgrade your os. */ +#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up" +#define usb_interface_t IOUSBInterfaceInterface +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID +#define LIBUSB_NO_TIMEOUT_INTERFACE +#define InterfaceVersion 180 + +#endif + +/* IOUSBDeviceInterface */ +#if defined (kIOUSBDeviceInterfaceID197) + +#define usb_device_t IOUSBDeviceInterface197 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 +#define DeviceVersion 197 + +#elif defined (kIOUSBDeviceInterfaceID187) + +#define usb_device_t IOUSBDeviceInterface187 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 +#define DeviceVersion 187 + +#elif defined (kIOUSBDeviceInterfaceID182) + +#define usb_device_t IOUSBDeviceInterface182 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 +#define DeviceVersion 182 + +#else + +#define usb_device_t IOUSBDeviceInterface +#define DeviceInterfaceID kIOUSBDeviceInterfaceID +#define LIBUSB_NO_TIMEOUT_DEVICE +#define LIBUSB_NO_SEIZE_DEVICE +#define DeviceVersion 180 + +#endif + +typedef IOReturn io_return_t; +typedef IOCFPlugInInterface *io_cf_plugin_ref_t; +typedef SInt32 s_int32_t; +typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size, + IOAsyncCallback1 callback, void *refcon); +typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size, + UInt32 noDataTimeout, UInt32 completionTimeout, + IOAsyncCallback1 callback, void *refcon); + +#if !defined(IO_OBJECT_NULL) +#define IO_OBJECT_NULL ((io_object_t)0) +#endif + +struct darwin_dev_handle { + usb_device_t **device; + usb_interface_t **interface; + int open; + + /* stored translation table for pipes to endpoints */ + int num_endpoints; + unsigned char *endpoint_addrs; +}; + +static IONotificationPortRef gNotifyPort; +static mach_port_t masterPort = MACH_PORT_NULL; + +static void darwin_cleanup (void) +{ + IONotificationPortDestroy(gNotifyPort); + mach_port_deallocate(mach_task_self(), masterPort); +} + +static char *darwin_error_str (int result) { + switch (result) { + case kIOReturnSuccess: + return "no error"; + case kIOReturnNotOpen: + return "device not opened for exclusive access"; + case kIOReturnNoDevice: + return "no connection to an IOService"; + case kIOUSBNoAsyncPortErr: + return "no async port has been opened for interface"; + case kIOReturnExclusiveAccess: + return "another process has device opened for exclusive access"; + case kIOUSBPipeStalled: + return "pipe is stalled"; + case kIOReturnError: + return "could not establish a connection to the Darwin kernel"; + case kIOUSBTransactionTimeout: + return "transaction timed out"; + case kIOReturnBadArgument: + return "invalid argument"; + case kIOReturnAborted: + return "transaction aborted"; + default: + return "unknown error"; + } +} + +/* not a valid errorno outside darwin.c */ +#define LUSBDARWINSTALL (ELAST+1) + +static int darwin_to_errno (int result) { + switch (result) { + case kIOReturnSuccess: + return 0; + case kIOReturnNotOpen: + return EBADF; + case kIOReturnNoDevice: + case kIOUSBNoAsyncPortErr: + return ENXIO; + case kIOReturnExclusiveAccess: + return EBUSY; + case kIOUSBPipeStalled: + return LUSBDARWINSTALL; + case kIOReturnBadArgument: + return EINVAL; + case kIOUSBTransactionTimeout: + return ETIMEDOUT; + case kIOReturnError: + default: + return 1; + } +} + +static int usb_setup_iterator (io_iterator_t *deviceIterator) +{ + int result; + CFMutableDictionaryRef matchingDict; + + /* set up the matching dictionary for class IOUSBDevice and its subclasses. + It will be consumed by the IOServiceGetMatchingServices call */ + if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) { + darwin_cleanup (); + + USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n"); + } + + result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator); + matchingDict = NULL; + + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n", + darwin_error_str(result)); + + return 0; +} + +static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) +{ + io_cf_plugin_ref_t *plugInInterface = NULL; + usb_device_t **device; + io_service_t usbDevice; + long result, score; + + if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator))) + return NULL; + + result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &plugInInterface, + &score); + + result = IOObjectRelease(usbDevice); + if (result || !plugInInterface) + return NULL; + + (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), + (LPVOID)&device); + + (*plugInInterface)->Stop(plugInInterface); + IODestroyPlugInInterface (plugInInterface); + plugInInterface = NULL; + + (*(device))->GetLocationID(device, locationp); + + return device; +} + +int usb_os_open(usb_dev_handle *dev) +{ + struct darwin_dev_handle *device; + + io_return_t result; + io_iterator_t deviceIterator; + + usb_device_t **darwin_device; + + UInt32 location = *((UInt32 *)dev->device->dev); + UInt32 dlocation; + + if (!dev) + USB_ERROR(-ENXIO); + + if (masterPort == MACH_PORT_NULL) + USB_ERROR(-EINVAL); + + device = calloc(1, sizeof(struct darwin_dev_handle)); + if (!device) + USB_ERROR(-ENOMEM); + + if (usb_debug > 3) + fprintf(stderr, "usb_os_open: %04x:%04x\n", + dev->device->descriptor.idVendor, + dev->device->descriptor.idProduct); + + if ((result = usb_setup_iterator (&deviceIterator)) < 0) + return result; + + /* This port of libusb uses locations to keep track of devices. */ + while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) { + if (dlocation == location) + break; + + (*darwin_device)->Release(darwin_device); + } + + IOObjectRelease(deviceIterator); + device->device = darwin_device; + + if (device->device == NULL) + USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!"); + +#if !defined (LIBUSB_NO_SEIZE_DEVICE) + result = (*(device->device))->USBDeviceOpenSeize (device->device); +#else + /* No Seize in OS X 10.0 (Darwin 1.4) */ + result = (*(device->device))->USBDeviceOpen (device->device); +#endif + + if (result != kIOReturnSuccess) { + switch (result) { + case kIOReturnExclusiveAccess: + if (usb_debug > 0) + fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result)); + break; + default: + (*(device->device))->Release (device->device); + USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s", + darwin_error_str(result)); + } + + device->open = 0; + } else + device->open = 1; + + dev->impl_info = device; + dev->interface = -1; + dev->altsetting = -1; + + device->num_endpoints = 0; + device->endpoint_addrs = NULL; + + return 0; +} + +int usb_os_close(usb_dev_handle *dev) +{ + struct darwin_dev_handle *device; + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + usb_release_interface(dev, dev->interface); + + if (usb_debug > 3) + fprintf(stderr, "usb_os_close: %04x:%04x\n", + dev->device->descriptor.idVendor, + dev->device->descriptor.idProduct); + + if (device->open == 1) + result = (*(device->device))->USBDeviceClose(device->device); + else + result = kIOReturnSuccess; + + /* device may not need to be released, but if it has to... */ + (*(device->device))->Release(device->device); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result)); + + free (device); + + return 0; +} + +static int get_endpoints (struct darwin_dev_handle *device) +{ + io_return_t ret; + + u_int8_t numep, direction, number; + u_int8_t dont_care1, dont_care3; + u_int16_t dont_care2; + + int i; + + if (device == NULL || device->interface == NULL) + return -EINVAL; + + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n"); + + /* retrieve the total number of endpoints on this interface */ + ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep); + if ( ret ) { + if ( usb_debug > 1 ) + fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface ); + + USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" ); + } + + free (device->endpoint_addrs); + device->endpoint_addrs = calloc (sizeof (unsigned char), numep); + + /* iterate through pipe references */ + for (i = 1 ; i <= numep ; i++) { + ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number, + &dont_care1, &dont_care2, &dont_care3); + + if (ret != kIOReturnSuccess) { + fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n", + i ); + USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret)); + } + + if (usb_debug > 1) + fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number); + + device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) | + (number & USB_ENDPOINT_ADDRESS_MASK)); + } + + device->num_endpoints = numep; + + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n"); + + return 0; +} + +static int claim_interface (usb_dev_handle *dev, int interface) +{ + io_iterator_t interface_iterator; + io_service_t usbInterface = IO_OBJECT_NULL; + io_return_t result; + io_cf_plugin_ref_t *plugInInterface = NULL; + + IOUSBFindInterfaceRequest request; + + struct darwin_dev_handle *device; + long score; + int current_interface; + + device = dev->impl_info; + + request.bInterfaceClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + request.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator); + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s", + darwin_error_str(result)); + + for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) { + usbInterface = IOIteratorNext(interface_iterator); + if ( usb_debug > 3 ) + fprintf ( stderr, "Interface %d of device is 0x%08x\n", + current_interface, usbInterface ); + } + + current_interface--; + + /* the interface iterator is no longer needed, release it */ + IOObjectRelease(interface_iterator); + + if (!usbInterface) { + u_int8_t nConfig; /* Index of configuration to use */ + IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */ + /* Only a composite class device with no vendor-specific driver will + be configured. Otherwise, we need to do it ourselves, or there + will be no interfaces for the device. */ + + if ( usb_debug > 3 ) + fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" ); + + result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig ); + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s", + darwin_error_str(result)); + + if (nConfig < 1) + USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations"); + else if ( nConfig > 1 && usb_debug > 0 ) + fprintf ( stderr, "claim_interface: device has more than one" + " configuration, using the first (warning)\n" ); + + if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: device has %d configuration%s\n", + (int)nConfig, (nConfig>1?"s":"") ); + + /* Always use the first configuration */ + result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc ); + if (result != kIOReturnSuccess) { + if (device->open == 1) { + (*(device->device))->USBDeviceClose ( (device->device) ); + (*(device->device))->Release ( (device->device) ); + } + + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s", + darwin_error_str(result)); + } else if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: configuration value is %d\n", + configDesc->bConfigurationValue ); + + if (device->open == 1) { + result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue ); + + if (result != kIOReturnSuccess) { + (*(device->device))->USBDeviceClose ( (device->device) ); + (*(device->device))->Release ( (device->device) ); + + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s", + darwin_error_str(result)); + } + + dev->config = configDesc->bConfigurationValue; + } + + request.bInterfaceClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + request.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + /* Now go back and get the chosen interface */ + result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator); + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s", + darwin_error_str(result)); + + for (current_interface = 0 ; current_interface <= interface ; current_interface++) { + usbInterface = IOIteratorNext(interface_iterator); + + if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n", + current_interface, usbInterface ); + } + current_interface--; + + /* the interface iterator is no longer needed, release it */ + IOObjectRelease(interface_iterator); + + if (!usbInterface) + USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL"); + } + + result = IOCreatePlugInInterfaceForService(usbInterface, + kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, &score); + /* No longer need the usbInterface object after getting the plug-in */ + result = IOObjectRelease(usbInterface); + if (result || !plugInInterface) + USB_ERROR(-ENOENT); + + /* Now create the device interface for the interface */ + result = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(InterfaceInterfaceID), + (LPVOID) &device->interface); + + /* No longer need the intermediate plug-in */ + (*plugInInterface)->Stop(plugInInterface); + IODestroyPlugInInterface (plugInInterface); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s", + darwin_error_str(result)); + + if (!device->interface) + USB_ERROR(-EACCES); + + if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n", + current_interface, device->interface); + + /* claim the interface */ + result = (*(device->interface))->USBInterfaceOpen(device->interface); + if (result) + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s", + darwin_error_str(result)); + + result = get_endpoints (device); + + if (result) { + /* this should not happen */ + usb_release_interface (dev, interface); + USB_ERROR_STR ( result, "claim_interface: could not build endpoint table"); + } + + return 0; +} + +int usb_set_configuration (usb_dev_handle *dev, int configuration) +{ + struct darwin_dev_handle *device; + io_return_t result; + int interface; + + if ( usb_debug > 3 ) + fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration ); + + if (!dev) + USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" ); + + if ((device = dev->impl_info) == NULL) + USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" ); + + /* Setting configuration will invalidate the interface, so we need + to reclaim it. First, dispose of existing interface, if any. */ + interface = dev->interface; + + if ( device->interface ) + usb_release_interface(dev, dev->interface); + + result = (*(device->device))->SetConfiguration(device->device, configuration); + + if (result) + USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s", + darwin_error_str(result)); + + /* Reclaim interface */ + if (interface != -1) + result = usb_claim_interface (dev, interface); + + dev->config = configuration; + + return result; +} + +int usb_claim_interface(usb_dev_handle *dev, int interface) +{ + struct darwin_dev_handle *device = dev->impl_info; + + io_return_t result; + + if ( usb_debug > 3 ) + fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface ); + + if (!device) + USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" ); + + if (!(device->device)) + USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" ); + + /* If we have already claimed an interface, release it */ + if ( device->interface ) + usb_release_interface(dev, dev->interface); + + result = claim_interface ( dev, interface ); + if ( result ) + USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" ); + + dev->interface = interface; + + /* interface is claimed and async IO is set up: return 0 */ + return 0; +} + +int usb_release_interface(usb_dev_handle *dev, int interface) +{ + struct darwin_dev_handle *device; + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + return 0; + + result = (*(device->interface))->USBInterfaceClose(device->interface); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s", + darwin_error_str(result)); + + result = (*(device->interface))->Release(device->interface); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s", + darwin_error_str(result)); + + device->interface = NULL; + + free (device->endpoint_addrs); + + device->num_endpoints = 0; + device->endpoint_addrs = NULL; + + dev->interface = -1; + dev->altsetting = -1; + + return 0; +} + +int usb_set_altinterface(usb_dev_handle *dev, int alternate) +{ + struct darwin_dev_handle *device; + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed"); + + result = (*(device->interface))->SetAlternateInterface(device->interface, alternate); + + if (result) + USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface"); + + dev->altsetting = alternate; + + result = get_endpoints (device); + if (result) { + /* this should not happen */ + USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table"); + } + + return 0; +} + +/* simple function that figures out what pipeRef is associated with an endpoint */ +static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep) +{ + int i; + + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n"); + + for (i = 0 ; i < device->num_endpoints ; i++) + if (device->endpoint_addrs[i] == ep) + return i + 1; + + /* No pipe found with the correct endpoint address */ + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep); + + return -1; +} + +static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + int pipeRef; + + u_int8_t transferType, direction, number, interval; + u_int16_t maxPacketSize; + + if (!dev) + USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" ); + + if ((device = dev->impl_info) == NULL) + USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" ); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened"); + + + /* Set up transfer */ + if ((pipeRef = ep_to_pipeRef(device, ep)) < 0) + USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" ); + + (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, + &transferType, &maxPacketSize, &interval); + /* Transfer set up complete */ + + if (usb_debug > 0) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep); + + /* Do bulk transfer */ + if (transferType == kUSBInterrupt && usb_debug > 3) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); + +#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE) + if ( transferType != kUSBInterrupt) { + if (usb_bt_read != 0) + result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout); + else + result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout); + + /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */ + if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled) + usb_clear_halt (dev, ep); + } else +#endif + { + if (usb_bt_read != 0) + result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size); + else + result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size); + } + + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result)); + + return size; +} + +#if 0 +/* NOT USED */ +/* argument to handle multiple parameters to rw_completed */ +struct rw_complete_arg { + UInt32 io_size; + IOReturn result; + CFRunLoopRef cf_loop; +}; + +static void rw_completed(void *refcon, io_return_t result, void *io_size) +{ + struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon; + + if (usb_debug > 2) + fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result), + (UInt32)io_size, result); + + rw_arg->io_size = (UInt32)io_size; + rw_arg->result = result; + + CFRunLoopStop(rw_arg->cf_loop); +} + +static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout, + rw_async_func_t rw_async, rw_async_to_func_t rw_async_to) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + CFRunLoopSourceRef cfSource; + int pipeRef; + + struct rw_complete_arg rw_arg; + + u_int8_t transferType; + + /* None of the values below are used in libusb for bulk transfers */ + u_int8_t direction, number, interval; + u_int16_t maxPacketSize; + + if (!dev) + USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" ); + + if ((device = dev->impl_info) == NULL) + USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" ); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened"); + + + /* Set up transfer */ + if ((pipeRef = ep_to_pipeRef(device, ep)) < 0) + USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" ); + + (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, + &transferType, &maxPacketSize, &interval); + + bzero((void *)&rw_arg, sizeof(struct rw_complete_arg)); + rw_arg.cf_loop = CFRunLoopGetCurrent(); + CFRetain (rw_arg.cf_loop); + + (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource); + CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); + /* Transfer set up complete */ + + if (usb_debug > 0) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", + size, ep); + + /* Bulk transfer */ + if (transferType == kUSBInterrupt && usb_debug > 3) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); + + if ( transferType != kUSBInterrupt && rw_async_to != NULL) + + result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout, + (IOAsyncCallback1)rw_completed, (void *)&rw_arg); + else + result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed, + (void *)&rw_arg); + + if (result == kIOReturnSuccess) { + /* wait for write to complete */ + if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) { + (*(device->interface))->AbortPipe(device->interface, pipeRef); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */ + if (usb_debug) + fprintf(stderr, "usb_bulk_transfer: timed out\n"); + } + } + + CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); + CFRelease (rw_arg.cf_loop); + + /* Check the return code of both the write and completion functions. */ + if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess && + rw_arg.result != kIOReturnAborted) ) { + int error_code; + char *error_str; + + if (result == kIOReturnSuccess) { + error_code = darwin_to_errno (rw_arg.result); + error_str = darwin_error_str (rw_arg.result); + } else { + error_code = darwin_to_errno(result); + error_str = darwin_error_str (result); + } + + if (transferType != kUSBInterrupt && rw_async_to != NULL) + USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str); + else + USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str); + } + + return rw_arg.io_size; +} +#endif + +int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) +{ + int result; + + if (dev == NULL || dev->impl_info == NULL) + return -EINVAL; + + if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0) + USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)"); + + return result; +} + +int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) +{ + int result; + + if (dev == NULL || dev->impl_info == NULL) + return -EINVAL; + + ep |= 0x80; + + if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0) + USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)"); + + return result; +} + +/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */ +int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + return usb_bulk_write (dev, ep, bytes, size, timeout); +} + +int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + return usb_bulk_read (dev, ep, bytes, size, timeout); +} + +int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, int timeout) +{ + struct darwin_dev_handle *device = dev->impl_info; + + io_return_t result; + +#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) + IOUSBDevRequestTO urequest; +#else + IOUSBDevRequest urequest; +#endif + + if (usb_debug >= 3) + fprintf(stderr, "usb_control_msg: %d %d %d %d %p %d %d\n", + requesttype, request, value, index, bytes, size, timeout); + + bzero(&urequest, sizeof(urequest)); + + urequest.bmRequestType = requesttype; + urequest.bRequest = request; + urequest.wValue = value; + urequest.wIndex = index; + urequest.wLength = size; + urequest.pData = bytes; +#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) + urequest.completionTimeout = timeout; + urequest.noDataTimeout = timeout; + + result = (*(device->device))->DeviceRequestTO(device->device, &urequest); +#else + result = (*(device->device))->DeviceRequest(device->device, &urequest); +#endif + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result)); + + /* Bytes transfered is stored in the wLenDone field*/ + return urequest.wLenDone; +} + +int usb_os_find_busses(struct usb_bus **busses) +{ + struct usb_bus *fbus = NULL; + + io_iterator_t deviceIterator; + io_return_t result; + + usb_device_t **device; + + UInt32 location; + + char buf[20]; + int i = 1; + + /* Create a master port for communication with IOKit (this should + have been created if the user called usb_init() )*/ + if (masterPort == MACH_PORT_NULL) { + usb_init (); + + if (masterPort == MACH_PORT_NULL) + USB_ERROR(-ENOENT); + } + + if ((result = usb_setup_iterator (&deviceIterator)) < 0) + return result; + + while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { + struct usb_bus *bus; + + if (location & 0x00ffffff) + continue; + + bus = calloc(1, sizeof(struct usb_bus)); + if (bus == NULL) + USB_ERROR(-ENOMEM); + + sprintf(buf, "%03i", i++); + bus->location = location; + + strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1); + bus->dirname[sizeof(bus->dirname) - 1] = 0; + + LIST_ADD(fbus, bus); + + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname); + + (*(device))->Release(device); + } + + IOObjectRelease(deviceIterator); + + *busses = fbus; + + return 0; +} + +int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) +{ + struct usb_device *fdev = NULL; + + io_iterator_t deviceIterator; + io_return_t result; + + usb_device_t **device; + + u_int16_t address; + UInt32 location; + UInt32 bus_loc = bus->location; + + /* for use in retrieving device description */ + IOUSBDevRequest req; + + /* a master port should have been created by usb_os_init */ + if (masterPort == MACH_PORT_NULL) + USB_ERROR(-ENOENT); + + if ((result = usb_setup_iterator (&deviceIterator)) < 0) + return result; + + /* Set up request for device descriptor */ + req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); + req.bRequest = kUSBRqGetDescriptor; + req.wValue = kUSBDeviceDesc << 8; + req.wIndex = 0; + req.wLength = sizeof(IOUSBDeviceDescriptor); + + + while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { + unsigned char device_desc[DEVICE_DESC_LENGTH]; + + result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address); + + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08lx\n", location); + + /* first byte of location appears to be associated with the device's bus */ + if (location >> 24 == bus_loc >> 24) { + struct usb_device *dev; + + dev = calloc(1, sizeof(struct usb_device)); + if (dev == NULL) + USB_ERROR(-ENOMEM); + + dev->bus = bus; + + req.pData = device_desc; + result = (*(device))->DeviceRequest(device, &req); + + usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor); + + sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address, + dev->descriptor.idVendor, dev->descriptor.idProduct, + dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass); + + dev->dev = (USBDeviceAddress *)malloc(4); + memcpy(dev->dev, &location, 4); + + LIST_ADD(fdev, dev); + + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08lx\n", + dev->filename, bus->dirname, location); + } + + /* release the device now */ + (*(device))->Release(device); + } + + IOObjectRelease(deviceIterator); + + *devices = fdev; + + return 0; +} + +int usb_os_determine_children(struct usb_bus *bus) +{ + /* Nothing yet */ + return 0; +} + +void usb_os_init(void) +{ + if (masterPort == MACH_PORT_NULL) { + IOMasterPort(masterPort, &masterPort); + + gNotifyPort = IONotificationPortCreate(masterPort); + } +} + +void usb_os_cleanup (void) +{ + if (masterPort != MACH_PORT_NULL) + darwin_cleanup (); +} + +int usb_resetep(usb_dev_handle *dev, unsigned int ep) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + int pipeRef; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed"); + + if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) + USB_ERROR(-EINVAL); + + result = (*(device->interface))->ResetPipe(device->interface, pipeRef); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result)); + + return 0; +} + +int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + int pipeRef; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed"); + + if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) + USB_ERROR(-EINVAL); + +#if (InterfaceVersion < 190) + result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef); +#else + /* newer versions of darwin support clearing additional bits on the device's endpoint */ + result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef); +#endif + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result)); + + return 0; +} + +int usb_reset(usb_dev_handle *dev) +{ + struct darwin_dev_handle *device; + + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + if (!device->device) + USB_ERROR_STR(-ENOENT, "usb_reset: no such device"); + + result = (*(device->device))->ResetDevice(device->device); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result)); + + return 0; +} diff --git a/mac/libusb/descriptors.c b/mac/libusb/descriptors.c new file mode 100644 index 000000000..0146a8209 --- /dev/null +++ b/mac/libusb/descriptors.c @@ -0,0 +1,520 @@ +/* + * Parses descriptors + * + * Copyright (c) 2001 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include +#include +#include +#include "usbi.h" + +int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, + unsigned char type, unsigned char index, void *buf, int size) +{ + memset(buf, 0, size); + + return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (type << 8) + index, 0, buf, size, 1000); +} + +int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size) +{ + memset(buf, 0, size); + + return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (type << 8) + index, 0, buf, size, 1000); +} + +int usb_parse_descriptor(unsigned char *source, char *description, void *dest) +{ + unsigned char *sp = source, *dp = dest; + uint16_t w; + uint32_t d; + char *cp; + + for (cp = description; *cp; cp++) { + switch (*cp) { + case 'b': /* 8-bit byte */ + *dp++ = *sp++; + break; + case 'w': /* 16-bit word, convert from little endian to CPU */ + w = (sp[1] << 8) | sp[0]; sp += 2; + dp += ((unsigned long)dp & 1); /* Align to word boundary */ + *((uint16_t *)dp) = w; dp += 2; + break; + case 'd': /* 32-bit dword, convert from little endian to CPU */ + d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4; + dp += ((unsigned long)dp & 2); /* Align to dword boundary */ + *((uint32_t *)dp) = d; dp += 4; + break; + /* These two characters are undocumented and just a hack for Linux */ + case 'W': /* 16-bit word, keep CPU endianess */ + dp += ((unsigned long)dp & 1); /* Align to word boundary */ + memcpy(dp, sp, 2); sp += 2; dp += 2; + break; + case 'D': /* 32-bit dword, keep CPU endianess */ + dp += ((unsigned long)dp & 2); /* Align to dword boundary */ + memcpy(dp, sp, 4); sp += 4; dp += 4; + break; + } + } + + return sp - source; +} + +/* + * This code looks surprisingly similar to the code I wrote for the Linux + * kernel. It's not a coincidence :) + */ + +static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) +{ + struct usb_descriptor_header header; + unsigned char *begin; + int parsed = 0, len, numskipped; + + usb_parse_descriptor(buffer, "bb", &header); + + /* Everything should be fine being passed into here, but we sanity */ + /* check JIC */ + if (header.bLength > size) { + if (usb_debug >= 1) + fprintf(stderr, "ran out of descriptors parsing\n"); + return -1; + } + + if (header.bDescriptorType != USB_DT_ENDPOINT) { + if (usb_debug >= 2) + fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n", + header.bDescriptorType, USB_DT_ENDPOINT); + return parsed; + } + + if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) + usb_parse_descriptor(buffer, "bbbbwbbb", endpoint); + else if (header.bLength >= ENDPOINT_DESC_LENGTH) + usb_parse_descriptor(buffer, "bbbbwb", endpoint); + + buffer += header.bLength; + size -= header.bLength; + parsed += header.bLength; + + /* Skip over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + begin = buffer; + numskipped = 0; + while (size >= DESC_HEADER_LENGTH) { + usb_parse_descriptor(buffer, "bb", &header); + + if (header.bLength < 2) { + if (usb_debug >= 1) + fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header.bDescriptorType == USB_DT_ENDPOINT) || + (header.bDescriptorType == USB_DT_INTERFACE) || + (header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE)) + break; + + if (usb_debug >= 1) + fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); + numskipped++; + + buffer += header.bLength; + size -= header.bLength; + parsed += header.bLength; + } + + if (numskipped && usb_debug >= 2) + fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for drivers */ + /* to later parse */ + len = (int)(buffer - begin); + if (!len) { + endpoint->extra = NULL; + endpoint->extralen = 0; + return parsed; + } + + endpoint->extra = malloc(len); + if (!endpoint->extra) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n"); + endpoint->extralen = 0; + return parsed; + } + + memcpy(endpoint->extra, begin, len); + endpoint->extralen = len; + + return parsed; +} + +static int usb_parse_interface(struct usb_interface *interface, + unsigned char *buffer, int size) +{ + int i, len, numskipped, retval, parsed = 0; + struct usb_descriptor_header header; + struct usb_interface_descriptor *ifp; + unsigned char *begin; + + interface->num_altsetting = 0; + + while (size >= INTERFACE_DESC_LENGTH) { + interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1)); + if (!interface->altsetting) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't malloc interface->altsetting\n"); + return -1; + } + + ifp = interface->altsetting + interface->num_altsetting; + interface->num_altsetting++; + + usb_parse_descriptor(buffer, "bbbbbbbbb", ifp); + + /* Skip over the interface */ + buffer += ifp->bLength; + parsed += ifp->bLength; + size -= ifp->bLength; + + begin = buffer; + numskipped = 0; + + /* Skip over any interface, class or vendor descriptors */ + while (size >= DESC_HEADER_LENGTH) { + usb_parse_descriptor(buffer, "bb", &header); + + if (header.bLength < 2) { + if (usb_debug >= 1) + fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header.bDescriptorType == USB_DT_INTERFACE) || + (header.bDescriptorType == USB_DT_ENDPOINT) || + (header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE)) + break; + + numskipped++; + + buffer += header.bLength; + parsed += header.bLength; + size -= header.bLength; + } + + if (numskipped && usb_debug >= 2) + fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (!len) { + ifp->extra = NULL; + ifp->extralen = 0; + } else { + ifp->extra = malloc(len); + if (!ifp->extra) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n"); + ifp->extralen = 0; + return -1; + } + memcpy(ifp->extra, begin, len); + ifp->extralen = len; + } + + /* Did we hit an unexpected descriptor? */ + usb_parse_descriptor(buffer, "bb", &header); + if ((size >= DESC_HEADER_LENGTH) && + ((header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE))) + return parsed; + + if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { + if (usb_debug >= 1) + fprintf(stderr, "too many endpoints\n"); + return -1; + } + + if (ifp->bNumEndpoints > 0) { + ifp->endpoint = (struct usb_endpoint_descriptor *) + malloc(ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); + if (!ifp->endpoint) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n"); + return -1; + } + + memset(ifp->endpoint, 0, ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); + + for (i = 0; i < ifp->bNumEndpoints; i++) { + usb_parse_descriptor(buffer, "bb", &header); + + if (header.bLength > size) { + if (usb_debug >= 1) + fprintf(stderr, "ran out of descriptors parsing\n"); + return -1; + } + + retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } + } else + ifp->endpoint = NULL; + + /* We check to see if it's an alternate to this one */ + ifp = (struct usb_interface_descriptor *)buffer; + if (size < USB_DT_INTERFACE_SIZE || + ifp->bDescriptorType != USB_DT_INTERFACE || + !ifp->bAlternateSetting) + return parsed; + } + + return parsed; +} + +int usb_parse_configuration(struct usb_config_descriptor *config, + unsigned char *buffer) +{ + int i, retval, size; + struct usb_descriptor_header header; + + usb_parse_descriptor(buffer, "bbwbbbbb", config); + size = config->wTotalLength; + + if (config->bNumInterfaces > USB_MAXINTERFACES) { + if (usb_debug >= 1) + fprintf(stderr, "too many interfaces\n"); + return -1; + } + + config->interface = (struct usb_interface *) + malloc(config->bNumInterfaces * + sizeof(struct usb_interface)); + if (!config->interface) { + if (usb_debug >= 1) + fprintf(stderr, "out of memory\n"); + return -1; + } + + memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface)); + + buffer += config->bLength; + size -= config->bLength; + + config->extra = NULL; + config->extralen = 0; + + for (i = 0; i < config->bNumInterfaces; i++) { + int numskipped, len; + unsigned char *begin; + + /* Skip over the rest of the Class Specific or Vendor */ + /* Specific descriptors */ + begin = buffer; + numskipped = 0; + while (size >= DESC_HEADER_LENGTH) { + usb_parse_descriptor(buffer, "bb", &header); + + if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { + if (usb_debug >= 1) + fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header.bDescriptorType == USB_DT_ENDPOINT) || + (header.bDescriptorType == USB_DT_INTERFACE) || + (header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE)) + break; + + if (usb_debug >= 2) + fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); + numskipped++; + + buffer += header.bLength; + size -= header.bLength; + } + + if (numskipped && usb_debug >= 2) + fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (len) { + /* FIXME: We should realloc and append here */ + if (!config->extralen) { + config->extra = malloc(len); + if (!config->extra) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for config extra descriptors\n"); + config->extralen = 0; + return -1; + } + + memcpy(config->extra, begin, len); + config->extralen = len; + } + } + + retval = usb_parse_interface(config->interface + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + size -= retval; + } + + return size; +} + +void usb_destroy_configuration(struct usb_device *dev) +{ + int c, i, j, k; + + if (!dev->config) + return; + + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + struct usb_config_descriptor *cf = &dev->config[c]; + + if (!cf->interface) + continue; + + for (i = 0; i < cf->bNumInterfaces; i++) { + struct usb_interface *ifp = &cf->interface[i]; + + if (!ifp->altsetting) + continue; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = &ifp->altsetting[j]; + + if (as->extra) + free(as->extra); + + if (!as->endpoint) + continue; + + for (k = 0; k < as->bNumEndpoints; k++) { + if (as->endpoint[k].extra) + free(as->endpoint[k].extra); + } + free(as->endpoint); + } + + free(ifp->altsetting); + } + + free(cf->interface); + } + + free(dev->config); +} + +void usb_fetch_and_parse_descriptors(usb_dev_handle *udev) +{ + struct usb_device *dev = udev->device; + int i; + + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { + if (usb_debug >= 1) + fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG); + return; + } + + if (dev->descriptor.bNumConfigurations < 1) { + if (usb_debug >= 1) + fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1); + return; + } + + dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); + if (!dev->config) { + if (usb_debug >= 1) + fprintf(stderr, "Unable to allocate memory for config descriptor\n"); + return; + } + + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor)); + + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + unsigned char buffer[8], *bigbuffer; + struct usb_config_descriptor config; + int res; + + /* Get the first 8 bytes so we can figure out what the total length is */ + res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8); + if (res < 8) { + if (usb_debug >= 1) { + if (res < 0) + fprintf(stderr, "Unable to get descriptor (%d)\n", res); + else + fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res); + } + + goto err; + } + + usb_parse_descriptor(buffer, "bbw", &config); + + bigbuffer = malloc(config.wTotalLength); + if (!bigbuffer) { + if (usb_debug >= 1) + fprintf(stderr, "Unable to allocate memory for descriptors\n"); + goto err; + } + + res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength); + if (res < config.wTotalLength) { + if (usb_debug >= 1) { + if (res < 0) + fprintf(stderr, "Unable to get descriptor (%d)\n", res); + else + fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res); + } + + free(bigbuffer); + goto err; + } + + res = usb_parse_configuration(&dev->config[i], bigbuffer); + if (usb_debug >= 2) { + if (res > 0) + fprintf(stderr, "Descriptor data still left\n"); + else if (res < 0) + fprintf(stderr, "Unable to parse descriptors\n"); + } + + free(bigbuffer); + } + + return; + +err: + free(dev->config); + + dev->config = NULL; +} + diff --git a/mac/libusb/error.c b/mac/libusb/error.c new file mode 100644 index 000000000..f7d496d66 --- /dev/null +++ b/mac/libusb/error.c @@ -0,0 +1,36 @@ +/* + * USB Error messages + * + * Copyright (c) 2000-2001 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include +#include + +#include "usb.h" +#include "error.h" + +char usb_error_str[1024] = ""; +int usb_error_errno = 0; +usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE; + +char *usb_strerror(void) +{ + switch (usb_error_type) { + case USB_ERROR_TYPE_NONE: + return "No error"; + case USB_ERROR_TYPE_STRING: + return usb_error_str; + case USB_ERROR_TYPE_ERRNO: + if (usb_error_errno > -USB_ERROR_BEGIN) + return strerror(usb_error_errno); + else + /* Any error we don't know falls under here */ + return "Unknown error"; + } + + return "Unknown error"; +} + diff --git a/mac/libusb/error.h b/mac/libusb/error.h new file mode 100644 index 000000000..173e6fd27 --- /dev/null +++ b/mac/libusb/error.h @@ -0,0 +1,31 @@ +#ifndef _ERROR_H_ +#define _ERROR_H_ + +typedef enum { + USB_ERROR_TYPE_NONE = 0, + USB_ERROR_TYPE_STRING, + USB_ERROR_TYPE_ERRNO, +} usb_error_type_t; + +extern char usb_error_str[1024]; +extern int usb_error_errno; +extern usb_error_type_t usb_error_type; + +#define USB_ERROR(x) \ + do { \ + usb_error_type = USB_ERROR_TYPE_ERRNO; \ + usb_error_errno = x; \ + return x; \ + } while (0) + +#define USB_ERROR_STR(x, format, args...) \ + do { \ + usb_error_type = USB_ERROR_TYPE_STRING; \ + snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ + if (usb_debug >= 2) \ + fprintf(stderr, "USB error: %s\n", usb_error_str); \ + return x; \ + } while (0) + +#endif /* _ERROR_H_ */ + diff --git a/mac/libusb/usb.c b/mac/libusb/usb.c new file mode 100644 index 000000000..9b8773e11 --- /dev/null +++ b/mac/libusb/usb.c @@ -0,0 +1,307 @@ +/* + * Main API entry point + * + * Copyright (c) 2000-2003 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include /* getenv */ +#include /* stderr */ +#include /* strcmp */ +#include + +#include "usbi.h" + +int usb_debug = 0; +struct usb_bus *usb_busses = NULL; + +int usb_find_busses(void) +{ + struct usb_bus *busses, *bus; + int ret, changes = 0; + + ret = usb_os_find_busses(&busses); + if (ret < 0) + return ret; + + /* + * Now walk through all of the busses we know about and compare against + * this new list. Any duplicates will be removed from the new list. + * If we don't find it in the new list, the bus was removed. Any + * busses still in the new list, are new to us. + */ + bus = usb_busses; + while (bus) { + int found = 0; + struct usb_bus *nbus, *tbus = bus->next; + + nbus = busses; + while (nbus) { + struct usb_bus *tnbus = nbus->next; + + if (!strcmp(bus->dirname, nbus->dirname)) { + /* Remove it from the new busses list */ + LIST_DEL(busses, nbus); + + usb_free_bus(nbus); + found = 1; + break; + } + + nbus = tnbus; + } + + if (!found) { + /* The bus was removed from the system */ + LIST_DEL(usb_busses, bus); + usb_free_bus(bus); + changes++; + } + + bus = tbus; + } + + /* + * Anything on the *busses list is new. So add them to usb_busses and + * process them like the new bus it is. + */ + bus = busses; + while (bus) { + struct usb_bus *tbus = bus->next; + + /* + * Remove it from the temporary list first and add it to the real + * usb_busses list. + */ + LIST_DEL(busses, bus); + + LIST_ADD(usb_busses, bus); + + changes++; + + bus = tbus; + } + + return changes; +} + +int usb_find_devices(void) +{ + struct usb_bus *bus; + int ret, changes = 0; + + for (bus = usb_busses; bus; bus = bus->next) { + struct usb_device *devices, *dev; + + /* Find all of the devices and put them into a temporary list */ + ret = usb_os_find_devices(bus, &devices); + if (ret < 0) + return ret; + + /* + * Now walk through all of the devices we know about and compare + * against this new list. Any duplicates will be removed from the new + * list. If we don't find it in the new list, the device was removed. + * Any devices still in the new list, are new to us. + */ + dev = bus->devices; + while (dev) { + int found = 0; + struct usb_device *ndev, *tdev = dev->next; + + ndev = devices; + while (ndev) { + struct usb_device *tndev = ndev->next; + + if (!strcmp(dev->filename, ndev->filename)) { + /* Remove it from the new devices list */ + LIST_DEL(devices, ndev); + + usb_free_dev(ndev); + found = 1; + break; + } + + ndev = tndev; + } + + if (!found) { + /* The device was removed from the system */ + LIST_DEL(bus->devices, dev); + usb_free_dev(dev); + changes++; + } + + dev = tdev; + } + + /* + * Anything on the *devices list is new. So add them to bus->devices and + * process them like the new device it is. + */ + dev = devices; + while (dev) { + struct usb_device *tdev = dev->next; + + /* + * Remove it from the temporary list first and add it to the real + * bus->devices list. + */ + LIST_DEL(devices, dev); + + LIST_ADD(bus->devices, dev); + + /* + * Some ports fetch the descriptors on scanning (like Linux) so we don't + * need to fetch them again. + */ + if (!dev->config) { + usb_dev_handle *udev; + + udev = usb_open(dev); + if (udev) { + usb_fetch_and_parse_descriptors(udev); + + usb_close(udev); + } + } + + changes++; + + dev = tdev; + } + + usb_os_determine_children(bus); + } + + return changes; +} + +void usb_set_debug(int level) +{ + if (usb_debug || level) + fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n", + level, level ? "on" : "off"); + + usb_debug = level; +} + +void usb_init(void) +{ + if (getenv("USB_DEBUG")) + usb_set_debug(atoi(getenv("USB_DEBUG"))); + + usb_os_init(); +} + +usb_dev_handle *usb_open(struct usb_device *dev) +{ + usb_dev_handle *udev; + + udev = malloc(sizeof(*udev)); + if (!udev) + return NULL; + + udev->fd = -1; + udev->device = dev; + udev->bus = dev->bus; + udev->config = udev->interface = udev->altsetting = -1; + + if (usb_os_open(udev) < 0) { + free(udev); + return NULL; + } + + return udev; +} + +int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, + size_t buflen) +{ + /* + * We can't use usb_get_descriptor() because it's lacking the index + * parameter. This will be fixed in libusb 1.0 + */ + return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000); +} + +int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen) +{ + char tbuf[255]; /* Some devices choke on size > 255 */ + int ret, langid, si, di; + + /* + * Asking for the zero'th index is special - it returns a string + * descriptor that contains all the language IDs supported by the + * device. Typically there aren't many - often only one. The + * language IDs are 16 bit numbers, and they start at the third byte + * in the descriptor. See USB 2.0 specification, section 9.6.7, for + * more information on this. */ + ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf)); + if (ret < 0) + return ret; + + if (ret < 4) + return -EIO; + + langid = tbuf[2] | (tbuf[3] << 8); + + ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf)); + if (ret < 0) + return ret; + + if (tbuf[1] != USB_DT_STRING) + return -EIO; + + if (tbuf[0] > ret) + return -EFBIG; + + for (di = 0, si = 2; si < tbuf[0]; si += 2) { + if (di >= (buflen - 1)) + break; + + if (tbuf[si + 1]) /* high byte */ + buf[di++] = '?'; + else + buf[di++] = tbuf[si]; + } + + buf[di] = 0; + + return di; +} + +int usb_close(usb_dev_handle *dev) +{ + int ret; + + ret = usb_os_close(dev); + free(dev); + + return ret; +} + +struct usb_device *usb_device(usb_dev_handle *dev) +{ + return dev->device; +} + +void usb_free_dev(struct usb_device *dev) +{ + usb_destroy_configuration(dev); + free(dev->children); + free(dev); +} + +struct usb_bus *usb_get_busses(void) +{ + return usb_busses; +} + +void usb_free_bus(struct usb_bus *bus) +{ + free(bus); +} + diff --git a/mac/libusb/usb.h b/mac/libusb/usb.h new file mode 100644 index 000000000..8e2fedda3 --- /dev/null +++ b/mac/libusb/usb.h @@ -0,0 +1,339 @@ +/* + * Prototypes, structure definitions and macros. + * + * Copyright (c) 2000-2003 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + * + * This file (and only this file) may alternatively be licensed under the + * BSD license as well, read LICENSE for details. + */ +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include +#include + +#include + +/* + * USB spec information + * + * This is all stuff grabbed from various USB specs and is pretty much + * not subject to change + */ + +/* + * Device and/or Interface Class codes + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_PTP 6 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 +#define USB_CLASS_VENDOR_SPEC 0xff + +/* + * Descriptor types + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 +#define USB_DT_HUB 0x29 + +/* + * Descriptor sizes per descriptor type + */ +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define USB_DT_HUB_NONVAR_SIZE 7 + +/* All standard descriptors have these 2 fields in common */ +struct usb_descriptor_header { + u_int8_t bLength; + u_int8_t bDescriptorType; +}; + +/* String descriptor */ +struct usb_string_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int16_t wData[1]; +}; + +/* HID descriptor */ +struct usb_hid_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int16_t bcdHID; + u_int8_t bCountryCode; + u_int8_t bNumDescriptors; + /* u_int8_t bReportDescriptorType; */ + /* u_int16_t wDescriptorLength; */ + /* ... */ +}; + +/* Endpoint descriptor */ +#define USB_MAXENDPOINTS 32 +struct usb_endpoint_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bEndpointAddress; + u_int8_t bmAttributes; + u_int16_t wMaxPacketSize; + u_int8_t bInterval; + u_int8_t bRefresh; + u_int8_t bSynchAddress; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_TYPE_CONTROL 0 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1 +#define USB_ENDPOINT_TYPE_BULK 2 +#define USB_ENDPOINT_TYPE_INTERRUPT 3 + +/* Interface descriptor */ +#define USB_MAXINTERFACES 32 +struct usb_interface_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bInterfaceNumber; + u_int8_t bAlternateSetting; + u_int8_t bNumEndpoints; + u_int8_t bInterfaceClass; + u_int8_t bInterfaceSubClass; + u_int8_t bInterfaceProtocol; + u_int8_t iInterface; + + struct usb_endpoint_descriptor *endpoint; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +#define USB_MAXALTSETTING 128 /* Hard limit */ +struct usb_interface { + struct usb_interface_descriptor *altsetting; + + int num_altsetting; +}; + +/* Configuration descriptor information.. */ +#define USB_MAXCONFIG 8 +struct usb_config_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int16_t wTotalLength; + u_int8_t bNumInterfaces; + u_int8_t bConfigurationValue; + u_int8_t iConfiguration; + u_int8_t bmAttributes; + u_int8_t MaxPower; + + struct usb_interface *interface; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +/* Device descriptor */ +struct usb_device_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int16_t bcdUSB; + u_int8_t bDeviceClass; + u_int8_t bDeviceSubClass; + u_int8_t bDeviceProtocol; + u_int8_t bMaxPacketSize0; + u_int16_t idVendor; + u_int16_t idProduct; + u_int16_t bcdDevice; + u_int8_t iManufacturer; + u_int8_t iProduct; + u_int8_t iSerialNumber; + u_int8_t bNumConfigurations; +}; + +struct usb_ctrl_setup { + u_int8_t bRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +}; + +/* + * Standard requests + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +/* 0x02 is reserved */ +#define USB_REQ_SET_FEATURE 0x03 +/* 0x04 is reserved */ +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Various libusb API related stuff + */ + +#define USB_ENDPOINT_IN 0x80 +#define USB_ENDPOINT_OUT 0x00 + +/* Error codes */ +#define USB_ERROR_BEGIN 500000 + +/* + * This is supposed to look weird. This file is generated from autoconf + * and I didn't want to make this too complicated. + */ +#define USB_LE16_TO_CPU NXSwapLittleShortToHost +#if 0 +#if 1 +#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0) +#else +#define USB_LE16_TO_CPU(x) +#endif +#endif + +/* Data types */ +struct usb_device; +struct usb_bus; + +/* + * To maintain compatibility with applications already built with libusb, + * we must only add entries to the end of this structure. NEVER delete or + * move members and only change types if you really know what you're doing. + */ +struct usb_device { + struct usb_device *next, *prev; + + char filename[PATH_MAX + 1]; + + struct usb_bus *bus; + + struct usb_device_descriptor descriptor; + struct usb_config_descriptor *config; + + void *dev; /* Darwin support */ + + u_int8_t devnum; + + unsigned char num_children; + struct usb_device **children; +}; + +struct usb_bus { + struct usb_bus *next, *prev; + + char dirname[PATH_MAX + 1]; + + struct usb_device *devices; + u_int32_t location; + + struct usb_device *root_dev; +}; + +struct usb_dev_handle; +typedef struct usb_dev_handle usb_dev_handle; + +/* Variables */ +extern struct usb_bus *usb_busses; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function prototypes */ + +/* usb.c */ +usb_dev_handle *usb_open(struct usb_device *dev); +int usb_close(usb_dev_handle *dev); +int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, + size_t buflen); +int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, + size_t buflen); + +/* descriptors.c */ +int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, + unsigned char type, unsigned char index, void *buf, int size); +int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size); + +/* .c */ +int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, int timeout); +int usb_set_configuration(usb_dev_handle *dev, int configuration); +int usb_claim_interface(usb_dev_handle *dev, int interface); +int usb_release_interface(usb_dev_handle *dev, int interface); +int usb_set_altinterface(usb_dev_handle *dev, int alternate); +int usb_resetep(usb_dev_handle *dev, unsigned int ep); +int usb_clear_halt(usb_dev_handle *dev, unsigned int ep); +int usb_reset(usb_dev_handle *dev); + +#if 0 +#define LIBUSB_HAS_GET_DRIVER_NP 1 +int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, + unsigned int namelen); +#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1 +int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface); +#endif + +char *usb_strerror(void); + +void usb_init(void); +void usb_set_debug(int level); +int usb_find_busses(void); +int usb_find_devices(void); +struct usb_device *usb_device(usb_dev_handle *dev); +struct usb_bus *usb_get_busses(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __USB_H__ */ diff --git a/mac/libusb/usbi.h b/mac/libusb/usbi.h new file mode 100644 index 000000000..5fe8c8ebb --- /dev/null +++ b/mac/libusb/usbi.h @@ -0,0 +1,74 @@ +#ifndef _USBI_H_ +#define _USBI_H_ + +#include "usb.h" + +#include "error.h" + +extern int usb_debug; + +/* Some quick and generic macros for the simple kind of lists we use */ +#define LIST_ADD(begin, ent) \ + do { \ + if (begin) { \ + ent->next = begin; \ + ent->next->prev = ent; \ + } else \ + ent->next = NULL; \ + ent->prev = NULL; \ + begin = ent; \ + } while(0) + +#define LIST_DEL(begin, ent) \ + do { \ + if (ent->prev) \ + ent->prev->next = ent->next; \ + else \ + begin = ent->next; \ + if (ent->next) \ + ent->next->prev = ent->prev; \ + ent->prev = NULL; \ + ent->next = NULL; \ + } while (0) + +#define DESC_HEADER_LENGTH 2 +#define DEVICE_DESC_LENGTH 18 +#define CONFIG_DESC_LENGTH 9 +#define INTERFACE_DESC_LENGTH 9 +#define ENDPOINT_DESC_LENGTH 7 +#define ENDPOINT_AUDIO_DESC_LENGTH 9 + +struct usb_dev_handle { + int fd; + + struct usb_bus *bus; + struct usb_device *device; + + int config; + int interface; + int altsetting; + + /* Added by RMT so implementations can store other per-open-device data */ + void *impl_info; +}; + +/* descriptors.c */ +int usb_parse_descriptor(unsigned char *source, char *description, void *dest); +int usb_parse_configuration(struct usb_config_descriptor *config, + unsigned char *buffer); +void usb_fetch_and_parse_descriptors(usb_dev_handle *udev); +void usb_destroy_configuration(struct usb_device *dev); + +/* OS specific routines */ +int usb_os_find_busses(struct usb_bus **busses); +int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices); +int usb_os_determine_children(struct usb_bus *bus); +void usb_os_init(void); +int usb_os_open(usb_dev_handle *dev); +int usb_os_close(usb_dev_handle *dev); + +void usb_free_dev(struct usb_device *dev); +void usb_free_bus(struct usb_bus *bus); + +#endif /* _USBI_H_ */ + -- 2.30.2